#include <boot/boot.h>
#include <macros.h>

.section .text
.global _dragon

_dragon:
	mov $0, %ax
	mov %ax, %ds
	mov %ax, %es
	mov %ax, %fs
	mov %ax, %ss
	mov $STACK_64_ADDR, %esp


# 加载GDT
	lgdt GdtPtr(%rip)
# 加载IDT
	lidt IdtPtr(%rip)

	movq reg64(%rip), %rax  # 刷新流水线
	pushq $SelectorCode64
	pushq %rax
	lretq



reg64:
	.quad enter_long_mode


enter_long_mode:
	# 重新加载cr3
	movq $SYSTEM_PML4_ADDR, %rax
	movq %rax, %cr3

	movq $0, %rax
	movq %rax, %ds
	movq %rax, %es
	movq %rax, %gs
	movq %rax, %ss
	movq $(KERNEL_BASE+STACK_64_ADDR), %rsp # 进入内核做准备

setup_idt:
	lea intr_comm(%rip), %rdx # 中断函数指针放入rdx
	mov $SelectorCode64, %rax
	shlq $16, %rax # 将段选择子放入rax的16~31位
	mov %dx, %ax # 将中断函数指针的0~8位放入rax的0~8位
	mov $(0b10001111<<40), %rcx 
	addq %rcx, %rax # 设置中断类型为陷阱门，40～47位
	movl %edx, %ecx
	shrl $16, %ecx # 将中断函数指针的16～31位放入cx寄存器
	shlq $48, %rcx 
	addq %rcx, %rax # 将中断函数指针的16～31位放入rcx寄存器的48～63位
	shrq $32, %rdx # 将中断函数指针的32～63位放入rdx中
	lea  IdtTable(%rip), %rdi
	movq $256, %rcx
1:
	mov %rax, (%rdi)
	mov %rdx, 8(%rdi)
	addq $16, %rdi
	loop 1b


setup_tss:
	leaq	TssVal(%rip),	%rdx
	xorq	%rax,	%rax
	xorq	%rcx,	%rcx
	movq	$0x89,	%rax
	shlq	$40,	%rax # 存在于内存中的系统段，类型是64位的有效的TSS
	movl	%edx,	%ecx
	shrl	$24,	%ecx
	shlq	$56,	%rcx # 将TSS指针的24～31位放到rcx的56～63位
	addq	%rcx,	%rax # 将系统类型放入rax的40～47位
	xorq	%rcx,	%rcx
	movl	%edx,	%ecx
	andl	$0xffffff,	%ecx # 清除24～31位，因之前已处理过
	shlq	$16,	%rcx # 将TSS指针的0～23位放入rcx的16～39位
	addq	%rcx,	%rax # 将TSS指针的0～23位放入rax的16～39位
	addq	$103,	%rax # TSS大小104-1，放入0~15-位
	leaq	GdtTable(%rip),	%rdi
	movq	%rax,	0x50(%rdi)
	shrq	$32,	%rdx
	movq	%rdx,	0x58(%rdi)

	// xorq %rax, %rax
	// mov	$0x50,	%ax
	// ltr	%ax


	# 开启中断
	sti

	movq go_to_system(%rip), %rax
	pushq $SelectorCode64
	pushq %rax
	lretq

go_to_system:
	.quad EnjoySystem


intr_comm:
	cld
	pushq	%rax
	pushq	%rbx
	pushq	%rcx
	pushq	%rdx
	pushq	%rbp
	pushq	%rdi
	pushq	%rsi

	pushq	%r8
	pushq	%r9
	pushq	%r10
	pushq	%r11
	pushq	%r12
	pushq	%r13
	pushq	%r14
	pushq	%r15

	movq	%es,	%rax
	pushq	%rax
	movq	%ds,	%rax
	pushq	%rax

	movq	$0x10,	%rax
	movq	%rax,	%ds
	movq	%rax,	%es

	
	mov    $unknown_int_msg_len, %rsi
	leaq	unknown_int_msg(%rip),	%rdi			/* leaq get address */
	callq	shows

1:
	jmp	1b	

	popq	%rax
	movq	%rax,	%ds
	popq	%rax
	movq	%rax,	%es

	popq	%r15
	popq	%r14
	popq	%r13
	popq	%r12
	popq	%r11
	popq	%r10
	popq	%r9
	popq	%r8

	popq	%rsi
	popq	%rdi
	popq	%rbp
	popq	%rdx
	popq	%rcx
	popq	%rbx
	popq	%rax
	iretq

unknown_int_msg:
	.asciz "Unknown interrupt or fault @ RIP\n"
	.equiv unknown_int_msg_len, .-unknown_int_msg

# 初始化页表结构
	.org 0x1000
# PML4
g_pml4:
	.quad SYSTEM_PDPT_ADDR|0x3
	.fill 255, 8, 0
	.quad SYSTEM_PDPT_ADDR|0x3
	.fill 255, 8, 0

	.org 0x2000
#PDPT
.global g_pdpt
g_pdpt:
	.quad SYSTEM_PDT_ADDR|0x3
	.fill 511, 8, 0

	.org 0x3000
# PDT
g_pdt:
	.quad 0x00000083    #pdt[0]
	.quad 0x00200083    #pdt[1]
	.quad 0x00400083    #pdt[2]
	.quad 0x00600083    #pdt[3]
	.quad 0x00800083    #pdt[4]
	.quad 0x00a00083    #pdt[5]
	.quad 0x00c00083    #pdt[6]
	.quad 0x00e00083    #pdt[7]
	.quad 0x01000083    #pdt[8]
	.quad 0xe0000083    #pdt[9] 虚拟地址: [0xffff800001200000=0x1200000]|物理地址: 0xe0000000
	.quad 0xe0200083    #pdt[10]
	.quad 0xe0400083    #pdt[11]
	.quad 0xe0600083    #pdt[12]
	.quad 0xe0800083    #pdt[13]
	.quad 0xe0a00083    #pdt[14]
	.quad 0xe0c00083    #pdt[15]
	.quad 0xe0e00083    #pdt[16]
	.quad 0xe1000083    #pdt[17]
	.fill 494, 8, 0



.align 8
.data

.global GdtTable
.global TssSeg
GdtTable:
	.quad 0                  # NULL descriptor
	.quad 0x00209a0000000000 # 系统代码段 64
	.quad 0x0000920000000000 # 系统数据段 64
	.quad 0x0020fa0000000000 # 用户代码段 64
	.quad 0x0000f20000000000 # 用户数据段 64
	.quad 0x00cf9a000000ffff # 系统代码段 32
	.quad 0x00cf92000000ffff # 系统数据段 32
	.quad 0x00cffa000000ffff # 用户代码段 32
	.quad 0x00cff2000000ffff # 用户数据段 32
	.quad 0
TssSeg: /* 10~11 TSS 跳过第9个全局描述符 在IA32-E模式下占128bit */
	.quad 0
	.quad 0
    .fill 52, 8, 0                  
    .equiv GdtLen, .-GdtTable


.global IdtTable
IdtTable:
	.fill 512, 8, 0
	.equiv IdtLen, .-IdtTable


.global TssVal
TssVal:
	.fill 13, 8, 0
	.equiv TssLen, .-TssVal

GdtPtr:
    .dc.w GdtLen-1
    .quad GdtTable
	
    .equiv SelectorCode64,  0x08
    .equiv SelectorData64,  0x10

IdtPtr:
	.dc.w IdtLen-1
	.quad  IdtTable


